﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SharpBolt.Collision.CollisionSprite;
using InductBase;

namespace SharpBolt.Collision
{
    public class Collider
    {
        Dictionary<string,List<string>> ChainedTags;

        Collider()
        {
            ChainedTags = new Dictionary<string, List<string>>();
        }
        public bool IsChained(string tagA, string tagB)
        {
            if (!ChainedTags.ContainsKey(tagA))
            {
                ChainedTags[tagA] = new List<string>();
                return false;
            }

            if (!ChainedTags[tagA].Contains(tagB)) return false;

            return true;
        }

        public void CollideSprites(CollisionSpriteInstance spriteA, CollisionSpriteInstance spriteB)
        {
            foreach (var shapeA in spriteA.CurrentFrame.Shapes)
            {
                foreach (var shapeB in spriteB.CurrentFrame.Shapes)
                {
                    if (IsChained(shapeA.Tag,shapeB.Tag))
                    {                                                
                        if (ParallelRectanglesIntersect(
                            Rec.FromLocationSize(shapeA.Transformation.Position, shapeA.Size * shapeA.Transformation.Scale),
                            Rec.FromLocationSize(shapeB.Transformation.Position, shapeB.Size * spriteB.Transformation.Scale)
                            ))
                        {
                            if (spriteA.Collided != null)
                            {
                                spriteA.Collided(
                                    this,
                                    new CollisionSpriteInstance.CollisionEventArgs(
                                        shapeA, shapeB, spriteA, spriteB));

                                spriteB.Collided(
                                    this,
                                    new CollisionSpriteInstance.CollisionEventArgs(
                                        shapeB, shapeA, spriteB, spriteA));
                            }
                        }
                    }
                }
            }
        }

        static public bool ParallelFixedRectanglesIntersect(Rec recA, Rec recB)
        {

            recA = recA.GetPositiveRectangle();
            recB = recB.GetPositiveRectangle();

            if (recA.Right <= recB.Left) return false;
            if (recA.Bottom <= recB.Top) return false;
            if (recA.Top >= recB.Bottom) return false;
            if (recA.Left >= recB.Right) return false;

            return true;
        }

        static public bool ParallelRectanglesIntersect(Rec recA, Rec recB)
        {

            //recA = recA.GetPositiveRectangle();
            //recB = recB.GetPositiveRectangle();

            if (recA.Right <= recB.Left) return false;
            if (recA.Bottom <= recB.Top) return false;
            if (recA.Top >= recB.Bottom) return false;
            if (recA.Left >= recB.Right) return false;
          
            return true;
        }

        static public bool RectanglesContains(Vec2 point, Rec rectangle, Transformation rectangleTransformation)
        {
            Vec2 localPoint = rectangleTransformation.FromTransformation(point);
            return rectangle.Contains(localPoint);
        }

        static public bool LinesIntersect(Vec2 startA, Vec2 endA, Vec2 startB, Vec2 endB)
        {
            return LinesIntersect(startA, endA, startB, endB, out Vec2.Null);    
        }

        static public bool LinesIntersect(Vec2 startA, Vec2 endA, Vec2 startB, Vec2 endB, out Vec2 point)
        {
            Vec2 vectorA = endA - startA;

            Vec2 newStartB  = (startB - startA).Rotate(-vectorA.GetRotation());
            Vec2 newEndB    = (endB - startA).Rotate(-vectorA.GetRotation());

            if ((newStartB.Y > 0) != (newEndB.Y >= 0))
            {
                double koef = Math.Abs(newStartB.Y/(newEndB.Y - newStartB.Y));
                point = Vec2.LinearTween(newStartB, newEndB, koef);
                if (point.X > 0 && point.X < vectorA.Length)
                {
                    point = Vec2.LinearTween(startB, endB, koef);
                    return true;
                }
            }

            point = Vec2.Null;
            return false;
        }
    }
}
